home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / info-service / gopher / Unix / GopherTools / jughead / jughead.0.9 / search.c < prev    next >
Encoding:
Text File  |  1993-05-24  |  38.7 KB  |  1,181 lines

  1. /*****************************************************************************
  2.  * File:    search.c
  3.  *
  4.  * Author:    Rhett "Jonzy" Jones
  5.  *        jonzy@cc.utah.edu
  6.  *
  7.  * Date:    March 6, 1993
  8.  *
  9.  * Modified:    March 15, 1993, by Rhett "Jonzy" Jones.
  10.  *        Added the ability to handle the -HUP interrupt.
  11.  *
  12.  *        March 16, 1993, by Rhett "Jonzy" Jones.
  13.  *        PrintPositions() will only return the collected items if
  14.  *        the number of these items is less 1024.  Modified
  15.  *        PostPositions() to watch for the case where A and B and C
  16.  *        yeilds (A and B) = NIL, thus this result anded with C will
  17.  *        no longer print the entire list C.  Oversight in my part.
  18.  *
  19.  *        March 27, 1993, by Rhett "Jonzy" Jones.
  20.  *        Moved the definition of PORT2USE to the Makefile.
  21.  *
  22.  *        March 28, 1993, by Rhett "Jonzy" Jones.
  23.  *        Added sun support with the inclusion of:
  24.  *        #ifdef sun include <unistd.h>.
  25.  *
  26.  *        March 31, 1993, by Mic Kaczmarczik: mic@bongo.cc.utexas.edu
  27.  *        Added support for an optional -p port flag when running as a
  28.  *        search engine .  Added the variable 'searchPort as a parameter
  29.  *        in DoSearch().
  30.  *
  31.  *        April 4, 1993, by Rhett "Jonzy" Jones.
  32.  *        Added the variables elements2do, indexName, hashName, ifp, and
  33.  *        hfp, the routines GetPositions(), WriteHashTables(), and
  34.  *        MakeHashTables(),
  35.  *        to support giving the user some feed back as to the status of
  36.  *        the program when building the index tables and the use of a
  37.  *        secondary hash table to limit the amount of memory used, and
  38.  *        modified GetDisplayString(), CreateWordsTree()
  39.  *
  40.  *        May 5, 1993, by Rhett "Jonzy" Jones.
  41.  *        Modified PostPositions(), and added GetAllPositions()
  42.  *        to support partial word searches.
  43.  *        Added the #define MAXITEMS2RETURN.
  44.  *
  45.  *        May 6, 1993, by Rhett "Jonzy" Jones.
  46.  *        Modified LogMessage() to return if neither logFile or debug is
  47.  *        true.  This was done for efficiency purposes only.
  48.  *        Changed the loop counter in CleanUp() from an int to a long.
  49.  *        Fixed a bug that caused a core dump if received the SIGHUP
  50.  *        signal more than once.  This was rectified by making
  51.  *        items[l].positions = NIL in CreateElements().  Oops!
  52.  *        Fixed a potential bug in CreateElements() by making sure
  53.  *        numElements
  54.  *        gets a long value instead of a short.
  55.  *        Added the #define SHOW_ITEMS_DURING_DEBUG to ease in debugging.
  56.  *        Did some code cleaning up.
  57.  *
  58.  *        May 8, 1993, by Rhett "Jonzy" Jones.
  59.  *        Added the routine PrintList(), and defined BOOLOP_DEBUG to
  60.  *        assist in fixed a problem in PostPositions(), which gave
  61.  *        incorrect results of "a* b* not c*".  Thank you
  62.  *        doyle@liberty.uc.wlu.edu for bringing this to my attention.
  63.  *
  64.  *
  65.  *        May 10, 1993, by Rhett "Jonzy" Jones.
  66.  *        Modified PostPositions() to correct a problem of a search on
  67.  *        "a and b and c", where if "a and b" evaluated to nothing, the
  68.  *        result of anding this result with c produced c.  Example:
  69.  *        "a and b and c" was the same as "a and b or c" if "a and b"
  70.  *        evaluated to nothing.  Thanks doyle@liberty.uc.wlu.edu for
  71.  *        bringing this to my attention.
  72.  *        Changed the format of the logfile by altering the string
  73.  *        "jughead-Search ->" to now be "jughead(port#) ->", where
  74.  *        port# is the port jughead was started up with.  This change
  75.  *        was at the request of doyle@liberty.uc.wlu.edu to indentify
  76.  *        which jughead daemon did the logging when more than one
  77.  *        jughead is logging to the same log file.  Added the variable
  78.  *        'port2log' to support this feature.
  79.  *
  80.  *        May 12, 1993, by Rhett "Jonzy" Jones.
  81.  *        doyle@liberty.uc.wlu.edu reported that "a and b" returns
  82.  *        'b' if 'a' did not exist, so ... back to the drawing board to
  83.  *        fix this one.
  84.  *
  85.  *        May 14, 1993, by Rhett "Jonzy" Jones.
  86.  *        doyle@liberty.uc.wlu.edu reported that "a and b" returns
  87.  *        'a' if 'b' did not exist.  I believe things are fixed now.
  88.  *
  89.  *        May 20, 1993, by Rhett "Jonzy" Jones.
  90.  *        Added the inclusion of sys/types.h, sys/socket.h, time.h,
  91.  *        and pwd.h.  Gave support for the -u username to change the
  92.  *        process uid when running jughead as a search engine.
  93.  *        Added the routine VerifyDataBaseName() to allow verification
  94.  *        of the database while allowing for the database to reside in
  95.  *        a directory other than jughead.  Thank you rzakon@mitre.org
  96.  *        for bringing this to my attention.
  97.  *
  98.  *        May 22, 1993, by Rhett "Jonzy" Jones.
  99.  *        Added DEFAULTBOOLOP, which is defined in the Makefile to
  100.  *        allow for an easy change of the default boolean operator
  101.  *        to use when no operator seperates word to search for.
  102.  *
  103.  *        May 23, 1993, by Rhett "Jonzy" Jones.
  104.  *        Gave support for special commands.  For information on these
  105.  *        commands consult either "searchCmnds.c", the man page, or
  106.  *        "About.jughead".
  107.  *
  108.  *        May 23, 1993, by Rhett "Jonzy" Jones.
  109.  *        At the request of doylej@liberty.uc.wlu.edu modified
  110.  *        PrintPositions() to return a link when there are more than
  111.  *        MAXITEMS2RETURN items.  The link has the form:
  112.  *            Name=xxx items found.  Please consolidate your request
  113.  *            Type=1
  114.  *            Port=the port number jughead was started under
  115.  *            Path=?all [the requested search]
  116.  *            Host=THEHOST as defined in the Makefile
  117.  *
  118.  *
  119.  *        May 24, 1993, by Rhett "Jonzy" Jones.
  120.  *        At the request of doylej@liberty.uc.wlu.edu gave support
  121.  *        for the "?range=start-stop what" special command.
  122.  *
  123.  * Description:    Either builds an index into a datafile, where the datafile
  124.  *        contains lines of gopher menu items (via jughead), or performs
  125.  *        boolean searches on words from the display string in the
  126.  *        datafile as read from the resultant index file.
  127.  *
  128.  *        When building the index we read from the datafile and for
  129.  *        each line we acquire the current line position in the file via
  130.  *        ftell(), and extract the display string excluding the first
  131.  *        character which is the item type, and break the display string
  132.  *        into words.  We then dump the word followed by a tab and the
  133.  *        position to a temporary file.  We then read from the temporary
  134.  *        file and build a binary tree containing words and a list of
  135.  *        postions, which is the line the word came from.  No word is
  136.  *        duplicated in the tree.  And finaly dump the binary tree to
  137.  *        a file with the following format:
  138.  *        dataFileNameIndexWasBuiltFrom    numberOfnodes
  139.  *        lenWord0    word0    0    1    3
  140.  *        lenWord1    word1    2    5
  141.  *        ...
  142.  *        lenThisWord    word_numberOfnodes-1    m    n
  143.  *
  144.  *        As of April 4, 1993, a hash table and an index table get built
  145.  *        where the hash table as the following format:
  146.  *        dataFileNameIndexWasBuiltFrom    numberOfnodes
  147.  *        lenWord0    word0    position_in_index_table
  148.  *        lenWord1    word1    position_in_index_table
  149.  *        ...
  150.  *        lenThisWord    word_numberOfnodes-1    position_in_index_table
  151.  *
  152.  *        and the index table has the following format:
  153.  *        number_of_positions    position1...position-number_of_positions
  154.  *
  155.  *        where: dataFileNameIndexWasBuiltFrom is the name of the data
  156.  *        file this index was built from, numberOfnodes is the number of
  157.  *        nodes in the tree, lenWordX is the number of characters in wordX
  158.  *        including the terminating null, wordX is the word followed by
  159.  *        the position in the data file the word came from.
  160.  *
  161.  *        When reading from the index file and doing boolean operations,
  162.  *        we read the index into memory, and acquire the string the user
  163.  *        wants to do a search on.  This string is then broken into words,
  164.  *        using the same mechanisim as breaking the display string into
  165.  *        words.  If a single word is found we print all lines from the
  166.  *        datafile in which the word exists in the display string.  If two
  167.  *        words are found it is taken to be word1 AND word2.  The boolean
  168.  *        operations currently supported are AND, NOT, OR.  All boolean
  169.  *        operations are evaluated left to right.
  170.  *
  171.  * Routines:        void     LogMessage(int sockfd,char *message);
  172.  *            char     *GetDisplayString(FILE *fp,long *pos);
  173.  *            int     CreateWordsTree(char *fileName);
  174.  *        static    ListType *GetPositions(long index);
  175.  *        static    void     WriteHashTables(TreeType *node);
  176.  *            void     MakeHashTables(char *fileName,TreeType *root);
  177.  *            short     ReservedWord(char *word);
  178.  *            short     ParseSearchString(char *string);
  179.  *        static    void     PrintPositions(ListType *node);
  180.  *        static    void     PrintList(ListType *l);
  181.  *            ListType *DoOperation(short op,ListType *l1,
  182.  *                          ListType *l2);
  183.  *            void     LogRequest(int sockfd);
  184.  *        static ListType     *GetAllPositions(long index,char *what2Find,
  185.  *                          char *asterik,
  186.  *                          size_t asterikPos,int sockfd);
  187.  *            void     PostPositions(char *what2find);
  188.  *        static    int     VerifyDataBaseName(char *fName,char *dName);
  189.  *            short     CreateElements(char *fileName);
  190.  *            void     CleanUp(void);
  191.  *            int     HangUpSignal(void);
  192.  *            void     DoSearch(char *indexTable,char *logFile,
  193.  *                      int searchPort);
  194.  *
  195.  * Bugs:    No known bugs.
  196.  *
  197.  * Copyright:    Copyright 1993, University of Utah Computer Center.
  198.  *        This source may be freely distributed as long as this copyright
  199.  *         notice remains intact, and is in no way used for any monetary
  200.  *         gain, by any institution, business, person, or persons.
  201.  *
  202.  ****************************************************************************/
  203.  
  204. #include <pwd.h>
  205. #include <setjmp.h>
  206. #include <signal.h>
  207. #include <stdio.h>
  208. #include <sys/types.h>
  209. #include <sys/socket.h>
  210. #include <time.h>
  211. #ifdef NEXT
  212. #    include <libc.h>
  213. #else
  214. #    include <stdlib.h>
  215. #endif
  216. #include <string.h>
  217. #include <fcntl.h>
  218. #include <netinet/in.h>
  219. #ifdef sun
  220. #    include <unistd.h>
  221. #endif
  222.  
  223. #include "tree.h"
  224. #include "utils.h"
  225.  
  226. /* Uncomment this if you want to look at the items after they are built. */
  227. /* #define SHOW_ITEMS_DURING_DEBUG */
  228. /* Uncomment this to assist in debugging the boolean operations. */
  229. /* #define BOOLOP_DEBUG */
  230.  
  231. #define MAXITEMS2RETURN    1024    /* The maximum items to return at once. */
  232.  
  233. #define NOOP         0    /* The NOOP operation. */
  234. #define AND         1    /* The AND operation. */
  235. #define OR         2    /* The OR  operation. */
  236. #define NOT         3    /* The NOT operation. */
  237. #define MAXWRDSNCMNDS    20    /* The allowable words and commands. */
  238.  
  239. #define HASHEXT        ".ih"    /* The hash table extention. */
  240. #define INDXEXT        ".ix"    /* The index table extention. */
  241. #define NINEBACKSPACES    "\b\b\b\b\b\b\b\b\b"
  242.  
  243. /* These are the characters that denote a separator for words. */
  244. #define DELIMITERS    " \t\n\f\r !\"#$%&\'()+,-./:;<=>?@[\\]^_`{|}~"
  245.  
  246. Element        *items = (Element *)NIL;    /* Array of words and file postions. */
  247. long        numElements,            /* Number of elements in 'items'. */
  248.         elements2do;            /* Number of elements left to do. */
  249. char        dataFileName[512],        /* The name of the data file. */
  250.         indexName[512],            /* Name of the index file. */
  251.         hashName[512],            /* Name of the hast file. */
  252.         *logFile = (char *)NIL,        /* Name of the file to log to. */
  253.         *wrdsNcmds[MAXWRDSNCMNDS + 1];    /* Array of words and commands. */
  254. short        numCommands;            /* The number of words and commands. */
  255. int        port2log;            /* The port being used for the log file. */
  256. jmp_buf        hupbuf;                /* The place to go if -HUP encountered. */
  257. FILE        *ifp = (FILE *)NIL,        /* Pointer to the index file. */
  258.         *hfp = (FILE *)NIL;        /* Pointer to the hash file. */
  259.  
  260. /* The following are defined in "jughead.c". */
  261. extern char    *userName;            /* Name of the user to run jughead under. */
  262. extern int    debug,                /* Are we debugging? */
  263.         time2process;            /* Do we calculate the time for a certain run? */
  264. extern time_t    startTime;            /* The time a run was started, for use with 'time2process'. */
  265.  
  266. extern long    lineNumber;            /* Defined in "dirTree.c". */
  267.  
  268. extern char    *SpecialCommand();        /* Defined in "searchCmnds.c". */
  269. /*****************************************************************************
  270.  * LogMessage logs the message 'message' to the end of the log file 'logFile'.
  271.  * The logging is the same as that found in gopherd.c from the University of
  272.  * Minnesota.
  273.  ****************************************************************************/
  274. void LogMessage(sockfd,message)
  275.     int        sockfd;        /* The socket file descriptor. */
  276.     char        *message;    /* The message to log. */
  277. {    static char    hostName[256],    /* Name of the host we are talking to. */
  278.             ip[256];    /* The hosts IP number. */
  279.     struct flock    lock;        /* Info to lock the log file. */
  280.     time_t        theTime;    /* The current time. */
  281.     char        *cTime,        /* The calendar time. */
  282.             *lineFeed,    /* Location of the line feed. */
  283.             logEntry[1024];    /* The entry to place in the log. */
  284.     int        theLog = -1;    /* The file to log to. */
  285.  
  286.     if (!logFile && !debug)        /* No sense is using the CPU. */
  287.         return;
  288.  
  289.     if (logFile)    /* Open the sucker. */
  290.         theLog = open(logFile,O_WRONLY | O_APPEND | O_CREAT,0644);
  291.  
  292.     hostName[0] = '\0';
  293.  
  294.     if (sockfd > -1)
  295.         IP2Hostname(sockfd,hostName,ip);
  296.     time(&theTime);
  297.     cTime = ctime(&theTime);
  298.     if (lineFeed = strchr(cTime,'\n'))    /* Get rid of the line feed. */
  299.         *lineFeed = '\0';
  300.     sprintf(logEntry,"%s %d %s : %s\n",cTime,getpid(),hostName,message);
  301.  
  302.     if (theLog != -1)
  303.         {
  304.         lock.l_type = F_WRLCK;
  305.         lock.l_whence = SEEK_SET;
  306.         lock.l_start = lock.l_len = 0L;
  307.         fcntl(theLog,F_SETLKW,&lock);        /* Lock the file so no one can write to it. */
  308.         lseek(theLog,0L,SEEK_END);        /* Make sure we are at the end of file. */
  309.         write(theLog,logEntry,strlen(logEntry));
  310.         lock.l_type = F_UNLCK;
  311.         fcntl(theLog,F_SETLKW,&lock);        /* Unlock the file. */
  312.         }
  313.  
  314.     if (logFile)    /* I guess we can close it now. */
  315.         close(theLog);
  316.  
  317.     if (debug)
  318.         fprintf(stderr,"%s",logEntry);
  319.  
  320.  
  321. }    /* LogMessage */
  322.  
  323. /*****************************************************************************
  324.  * GetDisplayString returns the display string portion of the gopher line
  325.  * contained in 'str'.  I should mention the item type, which is the first
  326.  * character in the display string, is skipped.
  327.  ****************************************************************************/
  328. char *GetDisplayString(fp,pos)
  329.     FILE        *fp;        /* The file we are reading. */
  330.     long        *pos;        /* Position in the file of the line. */
  331. {    static char    buf[2048];    /* Buffer for the display string. */
  332.     size_t        len;        /* Number of characters to the tab. */
  333.     static long    line = 0;    /* The line number in the file for error reporting. */
  334.     char        *s;        /* Pointer to the line we acquire from the file. */
  335.     short        error = 0;    /* Did we encounter an error? */
  336.  
  337.     if (!(--elements2do % 10))
  338.         fprintf(stderr,"%s%9ld",NINEBACKSPACES,elements2do);
  339.  
  340.     *pos = ftell(fp);
  341.     line++;
  342.  
  343.     if (fgets(buf,2048,fp))
  344.         if (s = strchr(buf,'\t'))
  345.             if ((len = (size_t)(s - buf)) > 0)
  346.                 {
  347.                 buf[len] = '\0';
  348.                 return(buf + 1);
  349.                 }
  350.             else
  351.                 error = 1;
  352.         else
  353.             error = 1;
  354.  
  355.     if (error)
  356.         {
  357.         fprintf(stderr,"%swarning: GetDisplayString found bad line, line = %ld.\n         ",NINEBACKSPACES,line);
  358.         pos = 0;
  359.         return("");
  360.         }
  361.  
  362.     return((char *)NIL);
  363.  
  364. }    /* GetDisplayString */
  365.  
  366. /*****************************************************************************
  367.  * CreateWordsTree creates a tree where each node of the tree contains a
  368.  * word and a list of file positions, representing the line the word is
  369.  * contained in.  It should be mentioned that the words are parsed from
  370.  * the display string according to the 
  371.  ****************************************************************************/
  372. int CreateWordsTree(fileName)
  373.     char    *fileName;    /* Name of the data file. */
  374. {    long    position;    /* Position in the file of the current line. */
  375.     FILE    *fpIn;        /* The data file we area reading from .*/
  376.     char    *dStr,        /* The display string with no leading item type. */        
  377.         *word;        /* A word from dStr. */
  378.     int    error = 0;    /* Did we get an error? */
  379.  
  380.     if (fpIn = fopen(fileName,"r"))
  381.         {
  382.         fprintf(stderr,"Building the words tree...\n");
  383.         fprintf(stderr,"%9ld",elements2do = NumberOfLines(fileName));
  384.  
  385.         while (dStr = GetDisplayString(fpIn,&position))
  386.             if (*dStr)
  387.                 for (word = strtok(dStr,DELIMITERS); word; word = strtok(NIL,DELIMITERS))
  388.                     BuildTree(&root,StrToLower(word),position);
  389.         fclose(fpIn);
  390.         fprintf(stderr,"%swords tree is now built.\n",NINEBACKSPACES);
  391.         }
  392.     else
  393.         error = fprintf(stderr,"error: CreateWordsTree could not open %s\n",fileName);
  394.  
  395.     return(!error);
  396.  
  397. }    /* CreateWordsTree */
  398.     
  399. /*****************************************************************************
  400.  * GetPositions returns a list of the file positions, which contains the
  401.  * gopher information to send the client we are talking to, or do a given
  402.  * operation on.
  403.  ****************************************************************************/
  404. static ListType *GetPositions(index)
  405.     long        index;
  406. {    FILE        *fp;
  407.     ListType    *list = (ListType *)NIL;
  408.     int        i,
  409.             numPos;
  410.     long        where;
  411.  
  412.     if (debug)
  413.         fprintf(stderr,"In GetPositions with index = %ld, items[%ld].word = [%s], items[%ld].positions = %ld\n",
  414.                 index,index,items[index].word,index,items[index].positions->where);
  415.     if (fp = fopen(indexName,"r"))
  416.         {
  417.         if (!fseek(fp,items[index].positions->where,SEEK_SET))
  418.             {
  419.             numPos = GetInt(fp);
  420. #ifdef BOOLOP_DEBUG
  421.             if (debug)
  422.                 fprintf(stderr,"\tnumPos = %d\n",numPos);
  423. #endif
  424.             for (i = 0; i < numPos; i++)
  425.                 {
  426.                 where = GetLong(fp);
  427. #ifdef BOOLOP_DEBUG
  428.                 if (debug)
  429.                     fprintf(stderr,"\twhere = %ld\n",where);
  430. #endif
  431.                 list = BuildList(list,where);
  432.                 }
  433.             }
  434.         else
  435.             fprintf(stderr,"error: GetPositions had fseek fail.\n");
  436.         fclose(fp);
  437.         }
  438.     else
  439.         fprintf(stderr,"error: GetPositions could not open %s for reading\n",indexName);
  440.     return(list);
  441.  
  442. }    /* GetPositions */
  443.  
  444. /*****************************************************************************
  445.  * WriteHashTables writes the information within the tree pointed to by 'node'
  446.  * to the hash table and the index table.
  447.  ****************************************************************************/
  448. static void WriteHashTables(node)
  449.     TreeType    *node;        /* The node to process. */
  450. {    ListType    *positions;    /* List with the positions. */
  451.  
  452.     if (node)
  453.         {
  454.         WriteHashTables(node->left);
  455.  
  456.         if (!(--elements2do % 10))
  457.             fprintf(stderr,"%s%9ld",NINEBACKSPACES,elements2do);
  458.  
  459.         fprintf(hfp,"%d\t%s\t%ld\n",(int)strlen(node->word) + 1,node->word,(long)ftell(ifp));
  460.  
  461.         fprintf(ifp,"\t%ld",NumberOfListNodes(node->positions));
  462.         for (positions = node->positions; positions; positions = positions->next)
  463.             fprintf(ifp,"\t%ld",positions->where);
  464.         fprintf(ifp,"\n"),++lineNumber;
  465.  
  466.         WriteHashTables(node->right);
  467.         }
  468.  
  469. }    /* WriteHashTables */
  470.  
  471. /*****************************************************************************
  472.  * MakeHashTables creates the hash and index table such that the hash table
  473.  * contains the data file to index, the number of elements to create, followed
  474.  * by each line containing the size of the word plus 1 for the null character,
  475.  * a tab, the word, tab, and the file position in the the index table.  The
  476.  * index table contains the number of file positions, tab, the file positions
  477.  * seperated by tabs on a single line.  Each file position in the index table
  478.  * is the position in the data file where the word found in the hash table
  479.  * is referencing.
  480.  ****************************************************************************/
  481. void MakeHashTables(fileName,root)
  482.     char        *fileName;    /* Name of the data file.*/
  483.     TreeType    *root;        /* The root of the tree. */
  484. {
  485.     fprintf(stderr,"Building the hash tables...\n");
  486.  
  487.     strcpy(indexName,fileName);
  488.     strcat(indexName,INDXEXT);
  489.     strcpy(hashName,fileName);
  490.     strcat(hashName,HASHEXT);
  491.  
  492.     if (!(ifp = fopen(indexName,"w")))
  493.         fprintf(stderr,"error: MakeHashTable could not open %s for writing\n",indexName);
  494.     if (!(hfp = fopen(hashName,"w")))
  495.         fprintf(stderr,"error: MakeHashTable could not open %s for writing\n",hashName);
  496.     if (!ifp || !hfp)
  497.         exit(-1);
  498.  
  499.     fprintf(hfp,"%s\t%ld\n",fileName,elements2do = NumberOfLeafs(root));
  500.     fprintf(stderr,"         ");    /* To support the use of the backspaces. */
  501.     WriteHashTables(root);
  502.  
  503.     fprintf(stderr,"%shash tables are completed.\n",NINEBACKSPACES);
  504.  
  505.     fclose(ifp);
  506.     fclose(hfp);
  507.     ifp = hfp = (FILE *)NIL;
  508.  
  509. }    /* MakeHashTables */
  510.  
  511. /*****************************************************************************
  512.  * ReservedWord returns true if 'word' is "AND", "OR", or "NOT", otherwise
  513.  * it returns false.  If 'word' is "AND" this routine returns 1, if 'word' is
  514.  * "OR" we return 2, if 'word' is "NOT" 3 gets returned.
  515.  ****************************************************************************/
  516. short ReservedWord(word)
  517.     char    *word;            /* The word we are checking if reserved. */
  518. {    int    len = strlen(word);    /* The length of 'word'. */
  519.  
  520.     switch (len)
  521.         {
  522.         case 2:
  523.             if ((word[0] == 'O' || word[0] == 'o') &&
  524.                 (word[1] == 'R' || word[1] == 'r'))
  525.                     {
  526.                     word[0] = 'O'; word[1] = 'R';
  527.                 return(OR);
  528.                 }
  529.             break;
  530.         case 3:
  531.             if ((word[0] == 'A' || word[0] == 'a') &&
  532.                 (word[1] == 'N' || word[1] == 'n') &&
  533.                 (word[2] == 'D' || word[2] == 'd'))
  534.                     {
  535.                     word[0] = 'A'; word[1] = 'N'; word[2] = 'D';
  536.                 return(AND);
  537.                 }
  538.             else if ((word[0] == 'N' || word[0] == 'n') &&
  539.                  (word[1] == 'O' || word[1] == 'o') &&
  540.                  (word[2] == 'T' || word[2] == 't'))
  541.                     {
  542.                     word[0] = 'N'; word[1] = 'O'; word[2] = 'T';
  543.                 return(NOT);
  544.                 }
  545.             break;
  546.         default:
  547.             break;
  548.         }
  549.  
  550.     return(NOOP);
  551.  
  552. }    /* ReservedWord */
  553.  
  554. /*****************************************************************************
  555.  * ParseSearchString parses 'string' into words and or commands which we do
  556.  * searches and boolean searches on.  All words and commands get placed into
  557.  * the array 'commands'.  If any word is "and", "or", or "not" it is taken to
  558.  * be the command AND, OR, or NOT respectivly.  If any 2 words are not
  559.  * seperated with a command, the command AND is implied to be the seperating
  560.  * command.
  561.  ****************************************************************************/
  562. short ParseSearchString(string)
  563.     char        *string;    /* The string we are parsing. */
  564. {    char        *word;        /* The word extracted from 'string'. */
  565.     short        lastOneReserved,/* Was the last word reserved? */
  566.             thisOneReserved;/* Is the current word reserved? */
  567.  
  568. #ifdef IN_THE_FUTURE
  569.     /* In the future the database to use will exist before the tab. */
  570.     if (time2process)
  571.         time(&startTime);
  572.  
  573.     if (!CreateElements(indexTable))
  574.         {
  575.         fprintf(stderr,"error: DoSearch could not create index tree.\n");
  576.         exit(-1);
  577.         }
  578.  
  579.     if (time2process)
  580.         PostTime2Process();
  581. #endif
  582.  
  583.     for (numCommands = 0, lastOneReserved = 1, word = strtok(string,DELIMITERS);
  584.          numCommands < MAXWRDSNCMNDS && word;
  585.          word = strtok(NIL,DELIMITERS))
  586.         {
  587.         thisOneReserved = ReservedWord(word);
  588.         if (!lastOneReserved && !thisOneReserved)
  589.             {
  590.             wrdsNcmds[numCommands++] = DEFAULTBOOLOP;
  591.             wrdsNcmds[numCommands++] = StrToLower(word);
  592.             }
  593.         else if (thisOneReserved)
  594.             wrdsNcmds[numCommands++] = word;
  595.         else
  596.             wrdsNcmds[numCommands++] = StrToLower(word);
  597.         lastOneReserved = thisOneReserved;
  598.         }
  599.  
  600.     return(numCommands);
  601.  
  602. }    /* ParseSearchString */
  603.  
  604. /*****************************************************************************
  605.  * PrintPositions sends the line of text from the data file, the index table
  606.  * was built from, whose postion in the file is specified by 'node->where'
  607.  * to stdout.
  608.  ****************************************************************************/
  609. static void PrintPositions(sockfd,node,limit,rangeStart,rangeEnd)
  610.     int        sockfd;        /* The socket file descriptor. */
  611.     ListType    *node;        /* The list we are printing. */
  612.     long        limit,        /* The max number of items to return. */
  613.             rangeStart,    /* The start of a range. */
  614.             rangeEnd;    /* The end of a range. */
  615. {    FILE        *fp;        /* Pointer to the file with the actual data. */
  616.     char        buf[2048];    /* Buffer for the line of text. */
  617.     long        i,        /* A loop counter. */
  618.             n;        /* The number of items to return. */
  619.  
  620.     /* If too many items create some links on the fly and send'em.*/
  621.     if (!rangeStart && limit == MAXITEMS2RETURN && (n = NumberOfListNodes(node)) > MAXITEMS2RETURN)
  622.         {
  623.         char    s[1024],    /* A temporary string. */
  624.             what[1024];    /* The search command - any special command. */
  625.  
  626.         /* Handle the "All 'n' items" directory. */
  627.         sprintf(s,"1All %ld items\t?all",n);
  628.         SendString(s);
  629.         for (what[0] = i = 0; i < numCommands; i++)
  630.             {
  631.             strcat(what," ");
  632.             strcat(what,wrdsNcmds[i]);
  633.             }
  634.         SendString(what);
  635.         sprintf(s,"\t%s\t%d\r\n",HOSTNAME,port2log);
  636.         SendString(s);
  637.  
  638.         /* Now handle the range directories. */
  639.         for (i = 0; i < n; i += limit)
  640.             {
  641.             rangeStart = i + 1;
  642.             if ((i + limit) < n)
  643.                 rangeEnd = i + limit;
  644.             else
  645.                 rangeEnd = n;
  646.             sprintf(s,"1items %ld to %ld\t?range=%ld-%ld %s\t%s\t%d\r\n",
  647.                 rangeStart,rangeEnd,rangeStart,rangeEnd,
  648.                 what,HOSTNAME,port2log);
  649.             SendString(s);
  650.             }
  651.  
  652.         sprintf(s,"TOO MANY ITEMS: %ld items found",n);
  653.         LogMessage(sockfd,s);
  654.         return;
  655.         }
  656.  
  657.     if (fp = fopen(dataFileName,"r"))
  658.         {
  659.         if (rangeStart)
  660.             {
  661.             /* Traverse node to the rangeStart item. */
  662.             for (i = 0; i < rangeStart - 1 && node; i++, node = node->next);
  663.  
  664.             /* Spit out range of items. */
  665.             for ( ; i < rangeEnd && node; i++, node = node->next)
  666.                 if (!fseek(fp,node->where,SEEK_SET))
  667.                     SendString(fgets(buf,2048,fp));
  668.             }
  669.         else if (limit < 0)
  670.             while (node)
  671.                 {
  672.                 if (!fseek(fp,node->where,SEEK_SET))
  673.                     SendString(fgets(buf,2048,fp));
  674.                 node = node->next;
  675.                 }
  676.         else for (n = 0; n < limit && node; n++, node = node->next)
  677.             if (!fseek(fp,node->where,SEEK_SET))
  678.                 SendString(fgets(buf,2048,fp));
  679.  
  680.         fclose(fp);
  681.         }
  682.     else
  683.         fprintf(stderr,"error: PrintPositions could not open data file %s\n",dataFileName);
  684.  
  685. }    /* PrintPositions */
  686.  
  687. #ifdef BOOLOP_DEBUG
  688. /*****************************************************************************
  689.  * PrintList prints the list 'l', and was written solely for debugging.
  690.  ****************************************************************************/
  691. static void PrintList(l)
  692.     ListType    *l;        /* The list to print. */
  693. {
  694.     if (debug)
  695.         while (l)
  696.             {
  697.             fprintf(stderr,"%10ld,",l->where);
  698.             l = l->next;
  699.             }
  700.  
  701. }    /* PrintList */
  702. #endif
  703.  
  704. /*****************************************************************************
  705.  * DoOperation returns a list which is the result of "l1 op l2" where 'l1' and
  706.  * 'l2' are lists, and 'op' is the operation to perform which is either the
  707.  * AND, OR, or NOT operation.
  708.  ****************************************************************************/
  709. ListType *DoOperation(op,l1,l2)
  710.     short        op;        /* The operation [AND,OR,NOT]. */
  711.     ListType    *l1,        /* A list we operate on. */
  712.             *l2;        /* The other list we operate on. */
  713. {    ListType    *result = (ListType *)NIL,/* The result of "l1 op l2". */
  714.             *t = (ListType *)NIL;    /* A pointer into 'l1' or 'l2'. */
  715.  
  716.     switch (op)
  717.         {
  718.         case AND:
  719.             while (l1 && l2)
  720.                 if (l1->where == l2->where)
  721.                     {
  722.                     result = BuildList(result,l1->where);
  723.                     l1 = l1->next;
  724.                     l2 = l2->next;
  725.                     }
  726.                 else if (l1->where < l2->where)
  727.                     l1 = l1->next;
  728.                 else if (l1->where > l2->where)
  729.                     l2 = l2->next;
  730.             break;
  731.         case OR:
  732.             while (l1 && l2)
  733.                 if (l1->where == l2->where)
  734.                     {
  735.                     result = BuildList(result,l1->where);
  736.                     l1 = l1->next;
  737.                     l2 = l2->next;
  738.                     }
  739.                 else if (l1->where < l2->where)
  740.                     {
  741.                     result = BuildList(result,l1->where);
  742.                     l1 = l1->next;
  743.                     }
  744.                 else if (l1->where > l2->where)
  745.                     {
  746.                     result = BuildList(result,l2->where);
  747.                     l2 = l2->next;
  748.                     }
  749.             if (l1)
  750.                 t = l1;
  751.             else if (l2)
  752.                 t = l2;
  753.             while (t)
  754.                 {
  755.                 result = BuildList(result,t->where);
  756.                 t = t->next;
  757.                 }
  758.             break;
  759.         case NOT:
  760.             while (l1 && l2)
  761.                 if (l1->where == l2->where)
  762.                     {
  763.                     l1 = l1->next;
  764.                     l2 = l2->next;
  765.                     }
  766.                 else if (l1->where < l2->where)
  767.                     {
  768.                     result = BuildList(result,l1->where);
  769.                     l1 = l1->next;
  770.                     }
  771.                 else if (l1->where > l2->where)
  772.                     l2 = l2->next;
  773.             while (l1)
  774.                 {
  775.                 result = BuildList(result,l1->where);
  776.                 l1 = l1->next;
  777.                 }
  778.             break;
  779.         default:
  780.             result = (ListType *)NIL;
  781.             break;
  782.         }
  783.  
  784.     return(result);
  785.  
  786. }    /* DoOperation */
  787.  
  788. /*****************************************************************************
  789.  * LogRequest simply writes the search request to the log file.
  790.  ****************************************************************************/
  791. void LogRequest(sockfd)
  792.     int        sockfd;        /* The socket to write to. */
  793. {    char        buf[1024];
  794.     short        i;
  795.  
  796.     if (!logFile && !debug)        /* No sense is using the CPU. */
  797.         return;
  798.  
  799.     sprintf(buf,"jughead(%d) -> ",port2log);
  800.     for (i = 0; i < numCommands; i++)
  801.         if (strlen(buf) + strlen(wrdsNcmds[i]) + 1 < 1024)
  802.             {
  803.             strcat(buf," ");
  804.             strcat(buf,wrdsNcmds[i]);
  805.             }
  806.         else
  807.             break;
  808.     LogMessage(sockfd,buf);
  809.  
  810. }    /* LogRequest */
  811.  
  812. /*****************************************************************************
  813.  * GetAllPositions acquires all the postitions of the partial word search by
  814.  * finding the start and end position, and then OR'ing these positions into
  815.  * a list which gets returned.  If 'what2Find' starts off with the wild card
  816.  * character, the asterik, we post a message to the user and return nil.
  817.  ****************************************************************************/
  818. static ListType *GetAllPositions(index,what2Find,asterik,asterikPos,sockfd)
  819.     long        index;        /* Index into the items array. */
  820.     char        *what2Find,    /* The word we are looking for. */
  821.             *asterik;    /* The position of the asterik. */
  822.     size_t        asterikPos;    /* Number of characters to look at. */
  823.     int        sockfd;        /* The socket file descriptor, errors only. */
  824. {    ListType    *theList = (ListType *)NIL,    /* The list to return. */
  825.             *list1   = (ListType *)NIL,    /* List of positions to OR against list2. */
  826.             *list2   = (ListType *)NIL;    /* List of positions to OR against list1. */
  827.     long        start,        /* Start of the partial word match. */
  828.             end;        /* End of the partial word match. */
  829.  
  830.     if (what2Find == asterik && *what2Find == '*')
  831.         {
  832.         char    s[1024];
  833.         sprintf(s,"0Invalid wildcard usage - cannot be the first character.\t\terror.host\t-1\r\n");
  834.         SendString(s);
  835.         sprintf(s,"INVALID WILDCARD USAGE: %s",what2Find);
  836.         LogMessage(sockfd,s);
  837.         return((ListType *)NIL);
  838.         }
  839.  
  840.     /* Find the starting and ending positions of the positions to return. */
  841.     for (start = index - 1; start >= 0        && !strncmp(what2Find,items[start].word,asterikPos); start--);
  842.     for (end   = index + 1; end < numElements && !strncmp(what2Find,items[ end ].word,asterikPos); end++);
  843.  
  844.     if (debug)
  845.         fprintf(stderr,"GetAllPositions found starting position = %ld, and ending position = %ld\n",start + 1,end - 1);
  846.  
  847.     /* Process the positions we will be returning. */
  848.     for (start++; start < end; start++)
  849.         if (!list1)
  850.             list1 = GetPositions(start);
  851.         else if (!list2)
  852.             {
  853.             list2 = GetPositions(start);
  854.             theList = DoOperation(OR,list1,list2);
  855.             DestroyList(list1);
  856.             DestroyList(list2);
  857.             list1 = theList;
  858.             list2 = (ListType *)NIL;
  859.             }
  860.  
  861.     /* We may have only got one hit, so make sure we return the information. */
  862.     if (!theList && list1)
  863.         theList = list1;
  864.  
  865.     return(theList);
  866.  
  867. }    /* GetAllPositions */
  868.  
  869. /*****************************************************************************
  870.  * PostPositions posts the result of doing the boolean operations on 'what2find'
  871.  * and checking for membership in 'array'.
  872.  ****************************************************************************/
  873. void PostPositions(sockfd,what2find)
  874.     int        sockfd;        /* The socket to write to. */
  875.     char        *what2find;    /* String with words and operations. */
  876. {    short        evaluate,    /* Do we evaluate the operation? */
  877.             i,        /* A loop counter. */
  878.             operater = NOOP,/* Either [NOOP,AND,OR,NOT]. */
  879.             reserved;    /* Is the current word reserved? */
  880.     long        index,        /* Index into the items array. */
  881.             rangeStart,    /* The start of a range. */
  882.             rangeEnd,    /* The end of a range. */
  883.             limit   = MAXITEMS2RETURN;    /* The max number of items to return. */
  884.     ListType    *list1  = (ListType *)NIL,    /* List of positions to operate against list2. */
  885.             *list2  = (ListType *)NIL,    /* List of positions to operate against list1. */
  886.             *result = (ListType *)NIL,    /* The result of "list1 operation list2'. */
  887.             *tList  = (ListType *)NIL;    /* Temporary list to support partial word searches. */
  888.     char         *asterik;    /* Is this a partial word search? */
  889.     size_t        asterikPos;    /* Number of characters to the asterik. */
  890.  
  891.     if (!(what2find = SpecialCommand(what2find,&limit,&rangeStart,&rangeEnd)))
  892.         return;
  893.     if (ParseSearchString(what2find))
  894.         {
  895.         LogRequest(sockfd);
  896.         for (evaluate = i = 0; i < numCommands; i++)
  897.             if (reserved = ReservedWord(wrdsNcmds[i]))
  898.                 operater = reserved;
  899.             else if ((index = BinarySearch(StrToLower(wrdsNcmds[i]),items,numElements,&asterik,&asterikPos)) >= 0)
  900.                 {
  901.                 if (asterik)    /* We have a partial word search. */
  902.                     tList = GetAllPositions(index,wrdsNcmds[i],asterik,asterikPos,sockfd);
  903.                 else
  904.                     tList = GetPositions(index);
  905.                 if (!list1 && !evaluate)
  906.                     {
  907.                     result = list1 = tList;
  908.                     evaluate = 1;
  909.                     }
  910.                 else if (!list2)
  911.                     {
  912.                     list2 = tList;
  913.  
  914.                     result = DoOperation(operater,list1,list2);
  915. #ifdef BOOLOP_DEBUG
  916.                     if (debug)
  917.                         {
  918.                         fprintf(stderr,"list1 ==> ");
  919.                         PrintList(list1);
  920.                         fprintf(stderr,"\nlist2 ==> ");
  921.                         PrintList(list2);
  922.                         fprintf(stderr,"\nresult ==> ");
  923.                         PrintList(result);
  924.                         fprintf(stderr,"\n");
  925.                         }
  926. #endif
  927.                     DestroyList(list1);
  928.                     DestroyList(list2);
  929.                     list1 = result;
  930.                     list2 = (ListType *)NIL;
  931.                     operater = NOOP;
  932.                     }
  933.                 }
  934.             else
  935.                 {
  936.                 char    message[256];
  937.                 sprintf(message,"COULD NOT FIND [%s]",wrdsNcmds[i]);
  938.                 LogMessage(sockfd,message);
  939.                 if (operater == AND)
  940.                     {
  941.                     DestroyList(result);
  942.                     result = list1 = (ListType *)NIL;
  943.                     }
  944.                 evaluate = 1;
  945.                 }
  946.  
  947.         if (result)
  948.             {
  949.             PrintPositions(sockfd,result,limit,rangeStart,rangeEnd);
  950.             DestroyList(result);
  951.             }
  952.         }
  953.  
  954. }    /* PostPositions */
  955.  
  956. /*****************************************************************************
  957.  * VerifyDataBaseName verifies we are dealing with the correct database.
  958.  * This routine returns true if we have the correct database and false
  959.  * otherwise.
  960.  ****************************************************************************/
  961. static int VerifyDataBaseName(fName,dName)
  962.     char    *fName,        /* The root name of the database. */
  963.         *dName;        /* The name we should be dealing with. */
  964. {    char    *str;        /* Position in fName where dName occurs. */
  965.  
  966.     if (str = strstr(fName,dName))
  967.         {
  968.         if (!strcmp(dName,str))
  969.             strcpy(dName,fName);
  970.         return(1);
  971.         }
  972.     return(0);
  973.  
  974. }    /* VerifyDataBaseName */
  975.  
  976. /*****************************************************************************
  977.  * CreateElements returns true if we could create the dynamic array 'items'
  978.  * and false othewise.
  979.  ****************************************************************************/
  980. short CreateElements(fileName)
  981.     char    *fileName;    /* The name of the file to read. */
  982. {    FILE    *fp;        /* Pointer to the file we are reading. */
  983.     long    l,        /* A loop counter. */
  984.         where;        /* The postions in the "data" file. */
  985.     short    strLen;        /* The size of the word. */
  986.  
  987.     strcpy(indexName,fileName);
  988.     strcat(indexName,INDXEXT);
  989.     strcpy(hashName,fileName);
  990.     strcat(hashName,HASHEXT);
  991.  
  992.     if (!(fp = fopen(fileName,"r")))
  993.         fprintf(stderr,"error: CreateElements could not open %s for reading\n",fileName);
  994.     if (!(hfp = fopen(hashName,"r")))
  995.         fprintf(stderr,"error: CreateElements could not open %s for reading\n",hashName);
  996.     if (!fp || !hfp)
  997.         return(0);
  998.  
  999.     (void)GetStr(hfp,dataFileName,512);
  1000.  
  1001.     if (!VerifyDataBaseName(fileName,dataFileName))
  1002.         {
  1003.         fprintf(stderr,"error: incompatible database, looking for [%s]\n",dataFileName);
  1004.         exit(-1);
  1005.         }
  1006.  
  1007.     numElements = GetLong(hfp);
  1008.     if (items = (Element *)malloc(numElements * sizeof(Element)))
  1009.         for (l = 0; l < numElements; l++)
  1010.             {
  1011.             strLen = (short)GetInt(hfp);
  1012.             if (items[l].word = (char *)malloc(strLen * sizeof(char)))
  1013.                 {
  1014.                 (void)GetStr(hfp,items[l].word,strLen);
  1015.                 where = GetLong(hfp);
  1016.                 items[l].positions = (ListType *)NIL;
  1017.                 items[l].positions = BuildList(items[l].positions,where);
  1018.                 }
  1019.             else
  1020.                 {
  1021.                 fprintf(stderr,"error: CreateElements could not get memory for string %ld\n",l);
  1022.                 exit(-1);
  1023.                 }
  1024.             }
  1025.     else
  1026.         {
  1027.         fprintf(stderr,"error: CreateElements could not get memory for the %ld items\n",numElements);
  1028.         exit(-1);
  1029.         }
  1030.  
  1031. #ifdef SHOW_ITEMS_DURING_DEBUG
  1032.     if (debug)
  1033.         {
  1034.         fprintf(stderr,"items looks like:\n");
  1035.         for (l = 0; l < numElements; l++)
  1036.             fprintf(stderr,"\t[%ld]\t[%s]\t%ld\n",l,items[l].word,items[l].positions->where);
  1037.         }
  1038. #endif
  1039.  
  1040.     fclose(fp);
  1041.     fclose(hfp);
  1042.     hfp = (FILE *)NIL;
  1043.     return(1);
  1044.  
  1045. }    /* CreateElements */
  1046.  
  1047. /*****************************************************************************
  1048.  * CleanUp simply frees up any memory used in the dynamic array 'items'.
  1049.  ****************************************************************************/
  1050. static void CleanUp()
  1051. {    long    i;    /* A loop counter. */
  1052.  
  1053.     for (i = 0; i < numElements; i++)
  1054.         {
  1055.         free(items[i].word);
  1056.         DestroyList(items[i].positions);
  1057.         }
  1058.     free(items);
  1059.     numElements = 0;
  1060.  
  1061. }    /* CleanUp */
  1062.  
  1063. /*****************************************************************************
  1064.  * HangUpSignal resets the hangup interrupt, and returns to the saved state.
  1065.  ****************************************************************************/
  1066. int HangUpSignal()
  1067. {
  1068.     signal(SIGHUP,HangUpSignal);        /* Set things for next time. */
  1069.  
  1070.     LogMessage(-1,"SIGHUP signal encountered");
  1071.     if (debug)
  1072.         fprintf(stderr,"Releasing memory ...");
  1073.  
  1074.     CleanUp();
  1075.     if (debug)
  1076.         fprintf(stderr,"\nRebuilding the binary tree.\n");
  1077.  
  1078.     longjmp(hupbuf,0);            /* Jump to the saved state. */
  1079.  
  1080. }    /* HangUpSignal */
  1081.  
  1082. /*****************************************************************************
  1083.  * DoSearch is the search server part of jughead.  This routine never
  1084.  * returns.
  1085.  ****************************************************************************/
  1086. void DoSearch(indexTable,logFile,searchPort)
  1087.     char            *indexTable,    /* Name of the index table file. */
  1088.                 *logFile;    /* The file to log to. */
  1089.     int            searchPort;    /* Port to use */
  1090. {    int            childspid,    /* The process ID of the child process. */
  1091.                 s,        /* The socket file descriptor. */
  1092.                 newS,        /* The new socket file descriptor. */
  1093.                 addressLen;    /* Size of the address space. */
  1094.     struct sockaddr_in    address;    /* Address of connecting entity. */
  1095.  
  1096.     fprintf(stderr,"jughead, Copyright 1993, University of Utah Computer Center\n");
  1097.     fprintf(stderr,"Using index table %s\n",indexTable);
  1098.     fprintf(stderr,"Using port %d\n",port2log = searchPort);
  1099.  
  1100.     if (userName)
  1101.         {
  1102.         struct passwd *pswd;
  1103.         if (pswd = getpwnam(userName))
  1104.             if (setuid(pswd->pw_uid))
  1105.                 {
  1106.                 fprintf(stderr,"error: could not setuid %ld (%s)\n",(long)pswd->pw_uid,userName);
  1107.                 exit(-1);
  1108.                 }
  1109.             else
  1110.                 fprintf(stderr,"Running with setuid %ld (%s)\n",(long)pswd->pw_uid,userName);
  1111.         else
  1112.             {
  1113.             fprintf(stderr,"error: could not find user %s\n",userName);
  1114.             exit(-1);
  1115.             }
  1116.         }
  1117.  
  1118.  
  1119.     if (logFile)
  1120.         {
  1121.         char    message[512];
  1122.         fprintf(stderr,"Logging to %s\n",logFile);
  1123.         strcpy(message,"STARTED UP ON ");
  1124.         strcat(message,indexTable);
  1125.         LogMessage(-1,message);
  1126.         }
  1127.  
  1128.     if ((s = ListenerEstablished(searchPort)) < 0)
  1129.         exit(-1);
  1130.  
  1131.     /* Set things up to handle the -HUP signal. */
  1132.     if (signal(SIGHUP,SIG_IGN) != SIG_IGN)
  1133.         signal(SIGHUP,HangUpSignal);
  1134.     setjmp(hupbuf);
  1135.  
  1136. #ifndef IN_THE_FUTURE
  1137.     if (time2process)
  1138.         time(&startTime);
  1139.  
  1140.     if (!CreateElements(indexTable))
  1141.         {
  1142.         fprintf(stderr,"error: DoSearch could not create index tree.\n");
  1143.         exit(-1);
  1144.         }
  1145.  
  1146.     if (time2process)
  1147.         PostTime2Process();
  1148. #endif
  1149.  
  1150.     if (debug)
  1151.         fprintf(stderr,"Ready for incoming connections.\n");
  1152.  
  1153.     while (1)    /* Wait for and handle all connections. */
  1154.         {
  1155.         addressLen = sizeof(address);
  1156.         if ((newS = accept(s,(struct sockaddr *)&address,&addressLen)) < 0)
  1157.             {
  1158.             fprintf(stderr,"error: DoSearch could not accept\n");
  1159.             exit(-1);
  1160.             }
  1161.         if ((childspid = fork()) < 0)
  1162.             {
  1163.             fprintf(stderr,"error: DoSearch could not fork\n");
  1164.             exit(-1);
  1165.             }
  1166.         else if (!childspid)    /* Child process so */
  1167.             {        /* close original socket */
  1168.             close(s);
  1169.             ProcessRequest(newS);
  1170. #ifdef IN_THE_FUTURE
  1171.             CleanUp();
  1172. #endif
  1173.             exit(0);
  1174.             }
  1175.  
  1176.         ChildProcess();        /* Wait for the childs process to die. */
  1177.         close(newS);        /* Close the new socket we opened. */
  1178.         }
  1179.  
  1180. }    /* DoSearch */
  1181.